﻿using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

namespace NFox.Runtime.Dll
{

    public class Function
    {

        internal MethodInfo MethodInfo;
        Library _owner;
        public bool Builded { private set; get; }
        public string Alias { private set; get; }
        public string EntryPoint { private set; get; }
        public IntPtr Ip { private set; get; }
        public CharSet CharSet { private set; get; }

        public Function(Library owner, string alias, IntPtr ip, string  entryPoint, CharSet charSet)
        {
            _owner = owner;
            Builded = false;
            Alias = alias;
            EntryPoint = entryPoint;
            Ip = ip;
            CharSet = charSet;
        }

        /// <summary>
        /// 动态创建函数
        /// </summary>
        /// <param name="paramTypes">参数类型数组</param>
        /// <param name="returnType">返回值类型</param>
        public void CreateMethod(Type[] paramTypes, Type returnType)
        {
            Builded = true;
            MethodBuilder methodBuilder =
                _owner.ModuleBuilder.DefinePInvokeMethod(
                    Alias,
                    _owner.Name,
                    EntryPoint,
                    MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
                    CallingConventions.Standard,
                    returnType,
                    paramTypes,
                    _owner.CallingConv,
                    CharSet);
            methodBuilder.SetImplementationFlags(
                methodBuilder.GetMethodImplementationFlags() |
                MethodImplAttributes.PreserveSig);
        }

        /// <summary>
        /// 动态调用Api过程
        /// </summary>
        /// <param name="pars">参数列表</param>
        public void Invoke(params object[] pars)
        {
            if (!Builded)
            {
                Type[] paramTypes = new Type[pars.Length];
                for (int i = 0; i < pars.Length; i++)
                    paramTypes[i] = pars[i].GetType();
                CreateMethod(paramTypes, null);
                _owner.CreateFunctions();
            }
            MethodInfo.Invoke(null, pars);
        }

        /// <summary>
        /// 动态调用Api函数
        /// </summary>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="pars">参数列表</param>
        /// <returns>函数返回值</returns>
        public TResult Invoke<TResult>(params object[] pars)
        {
            if (!Builded)
            {
                Type[] paramTypes = new Type[pars.Length];
                for (int i = 0; i < pars.Length; i++)
                    paramTypes[i] = pars[i].GetType();
                CreateMethod(paramTypes, typeof(TResult));
                _owner.CreateFunctions();
            }
            return (TResult)MethodInfo.Invoke(null, pars);
        }

    }



}
